﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Liju.Common
{
    /// <summary>
    /// IO控制器
    /// </summary>
    public class ModbusRTUIO
    {
        public  SerialPort serialPort;
        private readonly object serialLock = new object();
        // 默认通讯参数
        private int address = 1;
        private int baudRate = 9600;
        private int dataBits = 8;
        private Parity parity = Parity.None;
        private StopBits stopBits = StopBits.One;

        /// <summary>
        /// IO控制器串口号名称
        /// </summary>
        public static string PortName = string.Empty;

        public  bool IOConState = false;


        public int Address
        {
            get { return address; }
            set { address = value; }
        }

        public int BaudRate
        {
            get { return baudRate; }
            set { baudRate = value; }
        }

        public int DataBits
        {
            get { return dataBits; }
            set { dataBits = value; }
        }

        public Parity Parity
        {
            get { return parity; }
            set { parity = value; }
        }

        public StopBits StopBits
        {
            get { return stopBits; }
            set { stopBits = value; }
        }

        public ModbusRTUIO(string portName)
        {        
            lock (serialLock)
            {
                try
                {
                    serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                    serialPort.Open();
                    if (serialPort.IsOpen)
                    {
                        IOConState = true;
                    }
                    else
                    {
                        IOConState = false;
                    }
                }
                catch(Exception ex)
                {
                    throw ex;
                }
            }
        }

        public ModbusRTUIO()
        {
            try
            {
                if (serialPort == null && !string.IsNullOrWhiteSpace(PortName))
                {
                    serialPort = new SerialPort(PortName, 38400, Parity.None, 8, StopBits.One);
                    serialPort.ReadTimeout = 1000; // 读取超时时间
                    serialPort.WriteTimeout = 1000; // 写入超时时间
                    serialPort.Open(); // 打开串口
                    //SerialPortState = 1;
                    if (serialPort.IsOpen)
                    {
                        IOConState = true;
                    }
                    else
                    {
                        IOConState = false;
                    }
                            
                }
                if (serialPort != null && !serialPort.IsOpen)
                {

                }
            }
            catch
            {
                //SerialPortState = -1;
            }
        }

        // 发送Modbus RTU命令（十六进制字符串形式）
        public void SendHexCommand(string hexCommand)
        {
            lock (serialLock)
            {
                byte[] commandBytes = StringToByteArray(hexCommand);

                // 发送字节数组
                serialPort.Write(commandBytes, 0, commandBytes.Length);
            }
        }
        
        // 接收Modbus RTU响应
        public byte[] ReceiveResponse(int bytesToRead)
        {
            lock (serialLock)
            {
                byte[] buffer = new byte[bytesToRead];
                Thread.Sleep(50);
                serialPort.Read(buffer, 0, bytesToRead);
                return buffer;
            }
        }

        // 关闭串口连接
        public void Close()
        {
            lock (serialLock)
            {
                if (serialPort.IsOpen)
                {
                    serialPort.Close();
                }
            }
        }

        /// <summary>
        /// IO输出 关
        /// </summary>
        /// <param name="Number">寄存器地址最大16位</param>
        /// <returns></returns>
        public bool SetOutClose(int Number)
        {

            try
            {
                lock (serialLock)
                {
                    string Numberstr;
                    if (Number > 16)
                    {
                        return false;
                    }

                    if (Number < 10)
                    {
                        Numberstr = "0" + Number.ToString();
                    }
                    else
                    {
                        // 如果大于等于 10，则将数字转换为字母
                        char letter = (char)('A' + (Number - 10)); // 将 10 以上的数字转换为字母 A、B、C...
                        Numberstr = "0" + letter;
                    }

                    string CRCLo, CRCHi;
                    string str = "010600" + Numberstr + "0000";
                    Byte[] bytr = StringToByteArray(str);
                    // 调用方法进行 CRC 计算
                    ModbusCRC16.GetModbusCRC16(bytr, (ushort)bytr.Length, out CRCLo, out CRCHi);
                    str = str + CRCLo.ToString() + CRCHi.ToString();
                    SendHexCommand(str);
                 
                    Byte[] resultbyte = ReceiveResponse(8);
                    bytr = StringToByteArray(str);
                    //比较返回校验码
                    bool re = CompareByteArrays(bytr, resultbyte);
                    if (re)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }


            }
            catch (Exception)
            {

                return false;
            }

        }

        /// <summary>
        /// IO输出 开
        /// </summary>
        /// <param name="Number">寄存器地址最大16位</param>
        /// <returns></returns>
        public bool SetOutOpen(int Number)
        {
            try
            {
                lock (serialLock)
                {

                    string Numberstr;
                    if (Number > 16)
                    {
                        return false;
                    }
                    if (Number < 10)
                    {
                        Numberstr = "0" + Number.ToString();
                    }
                    else
                    {
                        // 如果大于等于 10，则将数字转换为字母
                        char letter = (char)('A' + (Number - 10)); // 将 10 以上的数字转换为字母 A、B、C...
                        Numberstr = "0" + letter;
                    }

                    string CRCLo, CRCHi;
                    string str = "010600" + Numberstr + "0001";
                    Byte[] bytr = StringToByteArray(str);
                    // 调用方法进行 CRC 计算
                    ModbusCRC16.GetModbusCRC16(bytr, (ushort)bytr.Length, out CRCLo, out CRCHi);
                    str = str + CRCLo.ToString() + CRCHi.ToString();
                    bytr = StringToByteArray(str);
                    SendHexCommand(str);
                    
                    Byte[] resultbyte = ReceiveResponse(8);
                    //比较返回校验码
                    bool re = CompareByteArrays(bytr, resultbyte);
                    if (re)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }

            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 获取所有16位in值
        /// </summary>
        /// <returns></returns>
        public bool []  GetInValueAll()
        {
            try
            {
                lock (serialLock)
                {
                    string str = "010400000010F1C6";
                    SendHexCommand(str);
                    Byte[] resultbyte = ReceiveResponse(37);
                    bool[] bol = ParseCommunication(resultbyte);
                    return bol;
                }
            }
            catch (Exception)
            {
                bool[] bol = new bool[1];
                return bol;
            }
        }

        static bool[] ParseCommunication(byte[] dataBytes)
        {
            // 跳过前三个字节
            List<bool> result = new List<bool>();

            for (int i = 4; i < dataBytes.Length - 1; i += 2)
            {
                byte byte1 = dataBytes[i];
                byte byte2 = dataBytes[i + 1];

                // 根据规则，第一个字节为0x01表示true，
                if (byte1 == 0x01|| byte2 == 0x01)
                {
                    result.Add(true);
                }
                else
                {
                    result.Add(false);
                }
               
            }

            return result.ToArray();
        }

        //对比返回字符串是否和发送字符串一致
        private bool CompareByteArrays(byte[] array1, byte[] array2)
        {
            // 如果数组长度不同，则数组不相等
            if (array1.Length != array2.Length)
            {
                return false;
            }

            // 逐个字节进行比较
            for (int i = 0; i < array1.Length; i++)
            {
                if (array1[i] != array2[i])
                {
                    return false;
                }
            }

            // 如果所有字节都相等，则数组相等
            return true;
        }

        // 将十六进制字符串转换为字节数组
        private byte[] StringToByteArray(string hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            return bytes;
        }


    }
}
